﻿using System;
using System.Globalization;
using System.Web;
using CkSoftware.GroupMe.Sdk.Core;
using CkSoftware.GroupMe.Sdk.Core.Dao;
using CkSoftware.GroupMe.Sdk.Core.Exceptions;

namespace CkSoftware.GroupMe.Sdk.Helpers.Authorization
{
	/// <summary>
	/// Helper class for client authentication / authorization.
	/// </summary>
	public class GroupMeClientAuthHelper
	{
		private const string AccessTokenQueryStringParamName = "access_token";

		private const string AuthorizeUrlFormat = "{0}/oauth/authorize?client_id={1}";

		private readonly string _apiBaseUrl;

		private readonly string _oAuthBaseUrl;

		/// <summary>
		/// Creates a new instance of the GroupMeClientAuthHelper.
		/// </summary>
		/// <param name="oAuthBaseUrl">The base url of the oauth service (default is 'https://oauth.groupme.com').</param>
		/// <param name="apiBaseUrl">The base GroupMe API service url (default is 'https://oauth.groupme.com/v3').</param>
		public GroupMeClientAuthHelper(string oAuthBaseUrl = "https://oauth.groupme.com",
			string apiBaseUrl = "https://api.groupme.com/v3")
		{
			_apiBaseUrl = apiBaseUrl;
			_oAuthBaseUrl = CleanupBaseUrlSlashes(oAuthBaseUrl);
		}

		/// <summary>
		/// Reads the GroupMe AccessToken out of the given HttpRequest and returns it.
		/// </summary>
		/// <param name="request">The HttpRequest where the access-token should be read.</param>
		/// <returns>Returns the AccessToken found in the given HttpRequest.</returns>
		/// <exception cref="GroupMeException">Thrown if there is no AccessToken inside the request.</exception>
		public string GetAccessTokenForAuthorizeRequest(HttpRequestBase request)
		{
			string accessToken = request.QueryString[AccessTokenQueryStringParamName];

			if (string.IsNullOrEmpty(accessToken))
			{
				throw new GroupMeException(new MetaData {Code = 500, Errors = new[] {"No AccessToken found in request."}});
			}

			return accessToken;
		}

		/// <summary>
		/// Converts the given GroupMe application client-id to a url which can be used to redirect the users-browser.
		/// </summary>
		/// <param name="clientId">The GroupMe application client-id which should be used.</param>
		/// <returns>Returns a full url to redirect the user where the user can authenticate itself.</returns>
		public string GetAuthenticationRedirectUrl(string clientId)
		{
			return string.Format(CultureInfo.CurrentCulture, AuthorizeUrlFormat, _oAuthBaseUrl, clientId);
		}

		/// <summary>
		/// Creates a new IWebApiAccess instance using the given AccessToken.
		/// </summary>
		/// <param name="accessToken">The AccessToken to use for the new WebApiAccess class.</param>
		/// <returns>Returns a new IWebApiAccess instance.</returns>
		/// <exception cref="GroupMeException">Thrown if there is no AccessToken inside the request.</exception>
		public IWebApiAccess GetWebApiAccessForAccessToken(string accessToken)
		{
			if (string.IsNullOrEmpty(accessToken))
			{
				throw new GroupMeException(new MetaData {Code = 500, Errors = new[] {"No AccessToken found in request."}});
			}

			return new WebApiAccess(_apiBaseUrl, accessToken);
		}

		/// <summary>
		/// Reads the GroupMe AccessToken out of the given HttpRequest and instantiates a new IWebApiAccess class with the given
		/// token.
		/// </summary>
		/// <param name="request">The HttpRequest where the access-token should be read.</param>
		/// <returns>Returns a new IWebApiAccess instance which can be used for all GroupMe API calls.</returns>
		/// <exception cref="GroupMeException">Thrown if there is no AccessToken inside the request.</exception>
		public IWebApiAccess GetWebApiAccessForAuthorizeRequest(HttpRequestBase request)
		{
			return GetWebApiAccessForAccessToken(GetAccessTokenForAuthorizeRequest(request));
		}

		private string CleanupBaseUrlSlashes(string url)
		{
			if (url.EndsWith("/", StringComparison.InvariantCultureIgnoreCase))
			{
				return url.Substring(0, url.Length - 1);
			}

			return url;
		}
	}
}